#!/usr/bin/python
# -*- coding: utf-8 -*-
#agentService的一部分，客户端程序
#code by HAWK.Li

import wmi

import ConfigParser, base64
import win32serviceutil, win32service, win32event
import SocketServer, threading, socket, subprocess

import os, sys, time, string
import csv, logging, re

import MyUtil,ServerInfo
import AgentUpdateClient
import sitecustomize

def version(cmds, cmd):
    """CMDServer_version : 1.5_2012-03-12_Release
    """
    return version.__doc__

def readCron(csvfile):
    '''首次读入定时调度配置，确认当前时间，设定离下一分钟的秒数，分析定时调度
*,*,*,*,*,c:\WINDOWS\NOTEPAD.EXE
*,*,*,*,*,e:\1.bat
    '''
    if os.path.isfile(csvfile):
        spamReader = csv.reader(open(csvfile))
        #初始化内存中的列表，计数器，注意这样会强制占用列表0单位
        global AMinutes, AHours, ADays, AMonths, AWeeks, ACmd, AExe
        AMinutes = ['AMinutes']
        AHours = ['AHours']
        ADays = ['ADays']
        AMonths = ['AMonths']
        AWeeks = ['AWeeks']
        ACmd = ['cmd']
        AExe = ["exe"]
        listcount = 1
        if os.path.isfile(csvfile):
            f = open(csvfile, "r")
            for eachline in f:
                e = eachline.split(',')
                if len(e) == 7:
                    AMinutes.append(e[0])
                    AHours.append(e[1])
                    ADays.append(e[2])
                    AMonths.append(e[3])
                    AWeeks.append(e[4])
                    ACmd.append(e[5])
                    AExe.append(e[6])
                    listcount = listcount + 1
                else:
                    pass
        return listcount
    else:
        print "配置文件找不到，退出"
        exit(3)
        
class cmdServerThread(threading.Thread):
    def __init__(self, threadname):
        threading.Thread.__init__(self, name=threadname)
        
    def run(self):
        try:
            srv = SocketServer.ThreadingTCPServer((CmdServerIP, int(CmdServerPort)), CmdServer)
            srv.serve_forever()
        except:
            writeLog("cmdServerThread.run Error:" + str(sys.exc_info()[0]) + str(sys.exc_info()[1]))

class ServerMonitorInfo(threading.Thread):
    """每分钟发送一次心跳
    """
    def __init__(self, threadname):
        threading.Thread.__init__(self, name=threadname)
    
    def run(self):
        while True:
            try:
                try:
                    cpuload = ServerInfo.getCPUUsage()
                except:
                    self.writeLog("ServerMonitorInfo.cpuload:" + str(sys.exc_info()[0]) + str(sys.exc_info()[1]))
                    cpuload = '999'
                mem = ServerInfo.getPhyMem()
                memload = int(mem[1])
                try:
                    disk = ServerInfo.getDiskWarning()
                except:
                    disk = "GetdiskstatusError."
                try:
                    send = MyUtil.SendMsgToDB()
                    send.send(_3ds.Encrypt('agentHeart;' + computerId))
                    send.sock.recv(sockSize)
                    send.send(_3ds.Encrypt("ServerMonitorInfo;" + str(computerId) + ";" + str(cpuload) + ";" + str(memload) + ";" + str(disk) + ";" + str(CmdServerIP)))
                    send.sock.recv(sockSize)
                    send.send(_3ds.Encrypt('end'))
                except:
                    print "ServerMonitorInfo.run.send.error:" + str(sys.exc_info()[0]) + str(sys.exc_info()[1])
                    writeLog("ServerMonitorInfo.run.send.error:" + str(sys.exc_info()[0]) + str(sys.exc_info()[1]))
                finally:
                    send.closeSock()
                    time.sleep(60)
            except:
                print "ServerMonitorInfo.run error:" + str(sys.exc_info()[0]) + str(sys.exc_info()[1])
                writeLog("ServerMonitorInfo.run error:" + str(sys.exc_info()[0]) + str(sys.exc_info()[1]))
                time.sleep(60)
    
class CmdServer(SocketServer.BaseRequestHandler):
    """本模块负责接收服务端的命令请求
    """
    def handle(self):
        try:
            while True:
                cmd = self.request.recv(sockSize)
                cmd = _3ds.Decrypt(cmd)
                print "recevied command: "+str(cmd)
                cmds = MyUtil.splitCmd(cmd)
                keys = cmds.keys()
                if len(keys) > 0:
                    if cmds['cmd'] in fm.keys():
                        self.request.sendall(str(fm[cmds['cmd']](cmds, cmd)))
                        break
                    else:
                        self.request.sendall("-1")
                        break
                else:
                    self.request.sendall("-1")
                    break
            self.request.close()
        except:
            self.request.close()
            writeLog("CmdServer.handle:" + str(sys.exc_info()[0]) + str(sys.exc_info()[1]))
            print "CmdServer.handle:" + str(sys.exc_info()[0]) + str(sys.exc_info()[1])

def cronlist(cmds, cmd):
    """返回agent守护进程列表--CMDServer只负责看，真正守护的工作由agentservice完成
    """
    exes = "|"
    for i, e in enumerate(AExe):
        if i <> 0:
            exes += str(e) + "|"
    return exes + "\n"

def cronAdd(cmds, cmd):
    """增加守护进程列表的方法
    cmd=cronadd,cronadd=*;*;*;*;*;c:\WINDOWS\NOTEPAD.EXE;NOTEPAD.EXE
    """
    try:
        if not 'cronadd' in cmds.keys():
            return "-1", "Lost cronadd.缺少cronadd参数".decode('gbk').encode("utf-8")
        cronNew = cmds['cronadd'].upper() + '\n'
        if not cronNew.find(';'):
            return "-1", "parameter Error.请使用;分号为分隔符".decode('gbk').encode("utf-8")
        cronNew = cronNew.replace(';', ',')
        if os.path.isfile(MyUtil.cur_file_dir() + '\\crontab.ini'):
            f = open(MyUtil.cur_file_dir() + '\\crontab.ini', "r+")
            cronMatch = False
            for eachLine in f:
                if cronNew == eachLine.upper():
                    cronMatch = True
                    break
                else:
                    cronMatch = False
            str1 = 'Find duplicate cron.'
            if not cronMatch:
                f.write(cronNew + '\n')
                str1 = 'cronadd OK.'
            f.close()
            return "1", str1
        else:
            return "-1", 'crontab.ini not found.'
    except:
        return "-1", "CronAdd.Error"
    
def cronRemove(cmds, cmd):
    """删除已有守护进程列表的方法
    cmd=cronremove,cronremove=*;*;*;*;*;c:\windows\notepad.exe
    """
    try:
        if not 'cronremove' in cmds.keys():
            return "-1", "Lost cronremove.缺少cronremove参数".decode('gbk').encode("utf-8")
        cronNew = cmds['cronremove'].upper() + '\n'
        if not cronNew.find(';'):
            return "-1", "parameter Error.请使用;分号为分隔符".decode('gbk').encode("utf-8")
        cronNew = cronNew.replace(';', ',')
        crons = ''
        if os.path.isfile(MyUtil.cur_file_dir() + '\\crontab.ini'):
            f = open(MyUtil.cur_file_dir() + '\\crontab.ini', "r+")
            cronMatch = False
            for eachLine in f:
                if cronNew == eachLine.upper():
                    cronMatch = True
                    break
                else:
                    crons += eachLine
                    cronMatch = False
            f.close()
            print crons
            if cronMatch:
                f = open(MyUtil.cur_file_dir() + '\\crontab.ini', "w")
                f.write(crons + '\n')
                str1 = 'cronRemove OK.'
                f.close()
            else:
                str1 = cmds['cronremove'] + ' Cron not found.'
            return "1", str1
        else:
            return "-1", 'crontab.ini not found.'
    except:
        return "-1", "CronRemove.Error"

def isOnLine(cmds, cmd):
    """返回CMDServer是否在线
    此方法已经没有使用，待删
    """
    return "存活\n"

def Cpassword(cmd, cmdStr):
    """更改CMDServer所在windows操作系统的密码
    """
    try:
        if not 'password' in cmd.keys():
            return "-1", "Lost password.参数不完整，缺少密码".decode('gbk').encode("utf-8")
        Cpass = cmd['password']
        Cpass1 = ''.join(Cpass.split())
        if Cpass1 <> Cpass:
            return "-1", 'Password has space.密码有空格不支持'.decode('gbk').encode("utf-8")
        if not 'account' in cmd.keys():
            return "-1", "Lost account.参数不完整，缺少账号".decode('gbk').encode("utf-8")
        account = cmd['account']
        restr = ""
        lines = os.popen("net user %s %s" % (account, Cpass) + ' 2>&1').readlines()
        for line in lines:
            restr += line
        writeLog(restr)
        return restr.decode('gbk').encode("utf-8")
    except:
        print "Cpassword Error:" + str(sys.exc_info()[0]) + str(sys.exc_info()[1])
        writeLog("Cpassword Error:" + str(sys.exc_info()[0]) + str(sys.exc_info()[1]))

def MyUnZIP(cmds, cmd):
    """收到命令后进行解压的方法
    cmd=unzip,unzipfile=c:\\a.zip,path=c:\\test
    """
    try:
        if not 'unzipfile' in cmds.keys():
            return "-1", "Lost unzip filename.缺少zip压缩文件参数".decode('gbk').encode("utf-8")
        if not 'path' in cmds.keys():
            return "-1", "Lost unzip path.缺少解压目录路径".decode('gbk').encode("utf-8")    
        #unzip方法只支持/，所以要转义
        zpath = cmds['path'].replace('\\', '/')
        zfile = cmds['unzipfile']
        if os.path.isfile(zfile):
            zfile = zfile.replace('\\', '/')
            result1 = MyUtil.UnZIP(zfile, zpath)
            if result1 <> '-1':
                return "1", "unzip OK.解压完成."
            else:
                return "-1", "unzip failed.解压失败."
        else:
            return "-1", 'zipfile not found.压缩文件未找到.'
    except:
        return "-1", "MyUnZIP.Error"
    

def command(cmds, cmd):
    """执行命令"""
    restr = ""
    lines = os.popen(cmds['command'] + ' 2>&1').readlines()
    for line in lines:
        restr += line
    #return restr.decode('gbk').encode("utf-8")
    #怀疑编码的问题在这里，默认不是GBK，但是一种unicode，所以按默认的文件codeutf-8已经转了，不能再用GBK做encoding
    #以下先试试看能否解决问题---待后续解决
    print restr
    if isinstance(restr, unicode):
        print "code is unicode!"
    else:
        print "code not unicode!"
    return restr.decode("CP936").encode("utf-8")

def forever():
    try:
        print "CmdServer启动".decode('utf-8').encode("gbk")
        writeLog('CmdServer Start')
        cmdserver = cmdServerThread("cmdserver")
        cmdserver.start()
        try:
            send = MyUtil.SendMsgToDB()
            send.send(_3ds.Encrypt('startAgent;' + computerId))
            send.sock.recv(sockSize)
            
            info1 = _3ds.Encrypt("insertServer;" + computerId + ";" + infos)
            send.send(info1)
            send.sock.recv(sockSize)
            send.send(_3ds.Encrypt('end'))
            send.closeSock()
        except:
            writeLog("CMDServer.handle:" + str(sys.exc_info()[0]) + str(sys.exc_info()[1]))
        serverinfo = ServerMonitorInfo("ServerMonitorInfo")
        serverinfo.start()
        serverinfo.join()
        cmdserver.join()
    except:
        print "runCron Error:" + str(sys.exc_info()[0]) + str(sys.exc_info()[1])
        writeLog("CMDServer.forever Error:" + str(sys.exc_info()[0]) + str(sys.exc_info()[1]))

def writeLog(info):
    """记录日志方法
    """
    try:
        log.output(info)
        
    except:
        print "writeLog Error:" + str(sys.exc_info()[0]) + str(sys.exc_info()[1])
        pass

def setLocalIP():
    #强写本地IP地址到配置文件中去
    cf1 = ConfigParser.ConfigParser()
    cf1.read(MyUtil.cur_file_dir() + "\\auto.ini")
    ipMac = ServerInfo.GetinnerIPMac()
    innerIP = str(ipMac[0])
    cf1.set("Configuration", "localIP", innerIP)
    cf1.write(open(MyUtil.cur_file_dir() + "\\auto.ini", "w"))
   
if __name__ == '__main__':
    global computerId, fm, sockSize, _3ds
    _3ds = MyUtil._secret()
    sockSize = 64000
    computerId = MyUtil.getComputerId()
    setLocalIP()
    fm = {
          "downloads":AgentUpdateClient.downloads,
          "updateself":AgentUpdateClient.updateSelf,
          "cronlist":cronlist,
          "agentlist":isOnLine,
          "command":command,
          "version":version,
          "password":Cpassword,
          "cronadd":cronAdd,
          "cronremove":cronRemove,
          "unzip":MyUnZIP
          }
    
    cf1 = ConfigParser.ConfigParser()
    cf1.read(MyUtil.cur_file_dir() + "\\agent.ini")
    cf2 = ConfigParser.ConfigParser()
    cf2.read(MyUtil.cur_file_dir() + "\\auto.ini")
    
    global CmdServerIP, CmdServerPort, DBIP, DBPort,CPUCores,infos
    path = cf1.get("main", "path").decode('gbk').encode("utf-8")
    logfile = cf1.get("main", "logfile").decode('gbk').encode("utf-8")
    
    updateServerIp = cf1.get("main", "UpdateServerIP").decode('gbk').encode("utf-8")
    AgentUpdateClient.serverIp = updateServerIp
    CmdServerIP = cf2.get("Configuration", "localIP").decode('gbk').encode("utf-8")
    CmdServerPort = cf1.get("main", "CmdServerPort").decode('gbk').encode("utf-8")
    MyUtil.DBIP = cf1.get("main", "DBIP").decode('gbk').encode("utf-8")
    MyUtil.DBPort = cf1.get("main", "DBPort").decode('gbk').encode("utf-8")
    try:
        innerIP = cf2.get("Configuration", "localIP").decode('gbk').encode("utf-8")
    except:
        innerIP = "getIP_Error"
    try:
        innerMAC = cf2.get("Configuration","localMACAddress").decode('gbk').encode("utf-8")
    except:
        innerMAC = "getMAC_Error"
    try:
        WAIIP = cf2.get("Configuration","OuterIP").decode('gbk').encode("utf-8")
    except:
        WAIIP = "getWAIIP_Error"
    try:
        OS = cf2.get("Configuration","OS").decode('gbk').encode("utf-8")
    except:
        OS = "getOS_Error"
    try:
        CodeSet = cf2.get("Configuration","CodeSet").decode('gbk').encode("utf-8")
    except:
        CodeSet = "getCodeSet_Error"
    try:
        CPUCores = cf2.get("Configuration","CPUCores").decode('gbk').encode("utf-8")
    except:
        CPUCores = '1'
    try:
        Hostname = cf2.get("Configuration","hostname").decode('gbk').encode("utf-8")
    except:
        Hostname = "getHostname_Error"
    try:
        getPlatform = cf2.get("Configuration","Platform").decode('gbk').encode("utf-8")
    except:
        getPlatform = "Windows"
    try:
        CPUInfo = cf2.get("Configuration","CPUInfo").decode('gbk').encode("utf-8")
    except:
        CPUInfo = "GetCPUInfo_Error"
    try:
        SysDir = cf2.get("Configuration","SystemDirectory").decode('gbk').encode("utf-8")
    except:
        SysDir = "GetSystemDir_Error"
    try:
        PHMEM = cf2.get("Configuration","Physicalmemory").decode('gbk').encode("utf-8")
    except:
        PHMEM = "GetPHMEM_Error"

    infos = str(innerIP+';'+WAIIP+';'+innerMAC+';'+OS+';'+Hostname+';'+SysDir+';'+CPUCores+';'+CPUInfo+';'+PHMEM+';'+CodeSet+';'+getPlatform)
    
    readCron(MyUtil.cur_file_dir() + '\\crontab.ini')
    
    global LOG, log
    LOG = os.path.join(path, logfile)
    log = MyUtil.CLogInfo(LOG)
    forever()
    log.close()
    
